#![allow(non_snake_case)]
#[macro_use]
extern crate log;

use common_uu::file::FileExtend;
use common_uu::req::get_vec;
use common_uu::{IResult, JsonV};
use rand::Rng;
use rpa_drive as drive;
use rpa_drive::DriverTrait;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::thread::sleep;
use std::time::Duration;

type Data = serde_json::Map<String, JsonV>;

/// 登录[滑块验证码官网-网易易盾]进行测试
fn main() -> IResult<()> {
    // 读取配置文件
    let _result = common_uu::toml_read::run_watch("config_rpa.toml")?;

    // 初始化日志
    common_uu::mylog::init_log("logs/examples-滑块验证码");

    let ref mut driver = drive::new(serde_json::Map::new())?;
    driver
        .navigate_to("https://dun.163.com/trial/sense")
        .unwrap();

    let total = 1000;
    let mut run_num = 0_f64;
    let mut err_num = 0;

    let mut success_num = 0;
    let mut fail_num = 0;

    let _ = retry_click(driver);
    for n in 1..=total {
        let b = loop_action(driver, n);
        if let Ok(b) = b {
            if b {
                _sleep(5, 10);
                let _ = retry_click(driver);
                success_num += 1;
            } else {
                _sleep(3, 5);
                fail_num += 1;
            }
            run_num += 1_f64;

            let success_rate = (success_num as f64 / run_num as f64) * 10000_f64;
            let success_rate = success_rate.ceil() / 100_f64;
            info!(
                "运行滑块验证码, 第{}次, 成功率:{}%, 成功次数:{}, 失败次数:{}",
                run_num, success_rate, success_num, fail_num
            );
        } else {
            err_num += 1;
            error!("运行出错: {}次, {:?}", err_num, b);
            let _ = retry_click(driver);
            _sleep(12, 30);
        }
    }

    sleep(Duration::from_secs(9999999999999));
    Ok(())
}

fn retry_click(driver: &mut dyn crate::DriverTrait<Data>) -> IResult<()> {
    driver.refresh()?;
    _sleep(2, 3);
    driver.click_by_content(".tcapt-tabs__container", "可疑用户-滑动拼图")?;
    _sleep(1, 3);
    driver.click(".tcapt_wrap2 .yidun_intelli-control .yidun_intelli-icon")?;
    _sleep(1, 3);

    driver.data().insert("456".to_string(), JsonV::Bool(false));

    Ok(())
}

fn loop_action(driver: &mut dyn crate::DriverTrait<Data>, n: u32) -> IResult<bool> {
    let image_el = ".u-fitem-capt .yidun_panel .yidun_bg-img";
    let image_big_name = format!("{}.jpg", n);
    let image_big_path = image_save(driver, image_el, image_big_name.as_str())?;
    let (_, _, bg_width, _) = driver.get_rec(image_el)?;

    driver.data().insert("123".to_string(), JsonV::Bool(false));

    let image_el = ".u-fitem-capt .yidun_panel .yidun_jigsaw";
    let image_name = format!("{}.png", n);
    let image_path = image_save(driver, image_el, image_name.as_str())?;
    _sleep(1, 3);
    //let x: f64 = etax_captcha::calc_x3(&image_path, &image_big_path);
    let x: f64 = 3.;
    let x = bg_width as f64 * x + 5.;
    debug!("x位置 像素: {}", x);

    // 移动
    driver.move_by_offset(".u-fitem-capt div.yidun_slider", x as i32, 0)?;
    _sleep(2, 3);

    let mut text = driver
        .get_value(".u-fitem-capt span.yidun-fallback__tip")
        .unwrap_or(String::from("失败"));
    if text.trim() == "" {
        text = String::from("失败");
    }
    info!("验证码拖动结果: {}", text);
    _sleep(2, 5);
    let b = text.contains("成功");
    if !b {
        {
            let p = image_big_path.replace(&image_big_name, "/失败");
            let _ = std::fs::create_dir(p);
        }

        {
            let new_name = image_big_path.replace(
                &image_big_name,
                format!("失败/{}", &image_big_name).as_str(),
            );
            std::fs::rename(&image_big_path, &new_name);
        }

        {
            let new_name2 =
                image_path.replace(&image_name, format!("失败/{}", &image_name).as_str());
            std::fs::rename(&image_path, &new_name2)?;
        }
    }

    Ok(b)
}

fn _sleep(start: u64, end: u64) {
    let mut rng = rand::thread_rng();
    let datetime = rng.gen_range(start, end);
    debug!("休眠{}秒", datetime);
    std::thread::sleep(std::time::Duration::from_secs(datetime));
}

/// 保存图片
pub fn image_save(
    driver: &dyn crate::DriverTrait<Data>,
    selector: &str,
    file_name: &str,
) -> IResult<String> {
    let url = driver
        .get_attribute(selector, "src")
        .map_err(|e| format!("获得图片src失败: {:?}", e))?;
    let url = match url {
        JsonV::String(s) => s,
        _ => Err(format!("获得图片src失败: {}", selector))?,
    };
    let p = File::create_temporary_folder2("etax_image")?;
    let mut path = Path::new(&p).to_path_buf();
    let _r = std::fs::create_dir(&path);
    debug!("image_save 新增文件夹: {:?}", &path);
    // let uuid_str = uuid::Uuid::new_v4().to_string().replacen("-", "", 4);
    path.push(format!("{}", file_name));
    let mut file = File::create(&path).map_err(|e| format!("新建图片错误: {:?}", e))?;
    let resp = get_vec(url).map_err(|e| format!("下载图片错误: {:?}", e))?;
    // resp.copy_to(&mut file)?;
    file.write_all(resp.as_slice())
        .map_err(|e| format!("下载图片[write_all]错误: {:?}", e))?;
    file.sync_all()
        .map_err(|e| format!("下载图片[sync_all]错误: {:?}", e))?;
    debug!("image_save: {:?}", &path);
    Ok(path.to_str().unwrap_or_default().to_string())
}
